// src/services/indicators.service.ts
// 保留原始功能，添加指标分析功能

import { RSI, MACD, BollingerBands, SMA, EMA, ATR } from 'technicalindicators';
// 引入MACD相关类型
import { TAKlineData, RSIResult, RSIOptions, MACDResult, MACDOptions, BOLLResult, BOLLOptions, SMAResult, SMAOptions, EMAResult, EMAOptions, ATRResult, ATROptions } from '../types/indicator.types';

export class IndicatorsService {
  // 保留原有的计算方法
  calculateRSI(klines: TAKlineData[], options: RSIOptions = { period: 6 }): RSIResult[] {
    // 检查K线数据
    if (!klines || klines.length === 0) {
      return [];
    }

    // 提取收盘价
    const closePrices = klines.map(kline => kline.close);
    const timestamps = klines.map(kline => kline.timestamp);

    // 计算RSI
    const rsiValues = RSI.calculate({
      period: options.period,
      values: closePrices
    });

    // 由于RSI计算需要前置数据，结果数量会比输入少period个
    // 将结果与对应的时间戳匹配
    const startIndex = klines.length - rsiValues.length;
    return rsiValues.map((value, index) => ({
      timestamp: timestamps[startIndex + index],
      value: value
    }));
  }

  // 添加RSI分析方法
  analyzeRSI(rsiValue: number): {
    status: 'overbought' | 'oversold' | 'neutral',
    message: string
  } {
    if (rsiValue > 70) {
      return {
        status: 'overbought',
        message: 'RSI > 70，可能超买'
      };
    } else if (rsiValue < 30) {
      return {
        status: 'oversold',
        message: 'RSI < 30，可能超卖'
      };
    }
    return {
      status: 'neutral',
      message: `RSI = ${rsiValue.toFixed(2)}，处于中性区间`
    };
  }

  // 添加RSI统计分析
  analyzeRSIStatistics(rsiResults: RSIResult[]): {
    min: number;
    max: number;
    avg: number;
    overboughtCount: number;
    oversoldCount: number;
    overboughtPercentage: number;
    oversoldPercentage: number;
  } {
    if (rsiResults.length === 0) {
      return {
        min: 0, max: 0, avg: 0,
        overboughtCount: 0, oversoldCount: 0,
        overboughtPercentage: 0, oversoldPercentage: 0
      };
    }

    const values = rsiResults.map(r => r.value);
    const min = Math.min(...values);
    const max = Math.max(...values);
    const avg = values.reduce((sum, val) => sum + val, 0) / values.length;

    const overboughtCount = values.filter(v => v >= 70).length;
    const oversoldCount = values.filter(v => v <= 30).length;

    return {
      min,
      max,
      avg,
      overboughtCount,
      oversoldCount,
      overboughtPercentage: (overboughtCount / values.length) * 100,
      oversoldPercentage: (oversoldCount / values.length) * 100
    };
  }

  /**
   * 计算简单移动平均线 (SMA)
   * @param klines K线数据
   * @param options SMA计算选项
   * @returns SMA计算结果数组
   */
  calculateSMA(klines: TAKlineData[], options: SMAOptions): SMAResult[] {
    if (!klines || klines.length === 0) {
      return [];
    }

    const closePrices = klines.map(kline => kline.close);
    const timestamps = klines.map(kline => kline.timestamp);

    const smaValues = SMA.calculate({
      period: options.period,
      values: closePrices
    });

    // 匹配结果与时间戳
    const startIndex = klines.length - smaValues.length;
    return smaValues.map((value, index) => ({
      timestamp: timestamps[startIndex + index],
      value: value
    }));
  }

  /**
   * 计算指数移动平均线 (EMA)
   * @param klines K线数据
   * @param options EMA计算选项
   * @returns EMA计算结果数组
   */
  calculateEMA(klines: TAKlineData[], options: EMAOptions): EMAResult[] {
    if (!klines || klines.length === 0) {
      return [];
    }

    const closePrices = klines.map(kline => kline.close);
    const timestamps = klines.map(kline => kline.timestamp);

    const emaValues = EMA.calculate({
      period: options.period,
      values: closePrices
    });

    // 匹配结果与时间戳
    const startIndex = klines.length - emaValues.length;
    return emaValues.map((value, index) => ({
      timestamp: timestamps[startIndex + index],
      value: value
    }));
  }

  /**
   * 计算平均真实波幅 (ATR)
   * @param klines K线数据
   * @param options ATR计算选项
   * @returns ATR计算结果数组
   */
  calculateATR(klines: TAKlineData[], options: ATROptions): ATRResult[] {
    if (!klines || klines.length < options.period) {
      return [];
    }

    const atrValues = ATR.calculate({
      period: options.period,
      high: klines.map(k => k.high),
      low: klines.map(k => k.low),
      close: klines.map(k => k.close),
    });

    // 匹配结果与时间戳
    const startIndex = klines.length - atrValues.length;
    return atrValues.map((value, index) => ({
      timestamp: klines[startIndex + index].timestamp,
      value: value
    }));
  }

  // 修改MACD计算方法，保持结果命名与OKX一致
  calculateMACD(
    klines: TAKlineData[],
    options: MACDOptions = { fastPeriod: 12, slowPeriod: 26, signalPeriod: 9 }
  ): MACDResult[] {
    // 检查K线数据
    if (!klines || klines.length === 0) {
      return [];
    }

    // 提取收盘价
    const closePrices = klines.map(kline => kline.close);
    const timestamps = klines.map(kline => kline.timestamp);

    // 计算MACD
    const macdResults = MACD.calculate({
      values: closePrices,
      fastPeriod: options.fastPeriod,
      slowPeriod: options.slowPeriod,
      signalPeriod: options.signalPeriod,
      SimpleMAOscillator: false,
      SimpleMASignal: false
    });

    // 将结果与对应的时间戳匹配，并使用OKX交易所的命名约定
    const startIndex = klines.length - macdResults.length;
    return macdResults.map((result, index) => ({
      timestamp: timestamps[startIndex + index],
      DIF: result.MACD || 0,      // 差离值(原MACD)
      DEA: result.signal || 0,     // 平滑异同平均(原signal)
      MACD: result.histogram || 0  // 柱状图值(原histogram), DIF-DEA的差值
    }));
  }

  // 修改布林带计算方法使用新的类型
  calculateBollingerBands(
    klines: TAKlineData[],
    options: BOLLOptions = { period: 21, stdDev: 2 }
  ): BOLLResult[] {
    // 检查K线数据
    if (!klines || klines.length === 0) {
      return [];
    }

    // 提取收盘价
    const closePrices = klines.map(kline => kline.close);
    const timestamps = klines.map(kline => kline.timestamp);

    // 计算布林带
    const bbResults = BollingerBands.calculate({
      period: options.period,
      values: closePrices,
      stdDev: options.stdDev
    });

    // 将结果与对应的时间戳匹配
    const startIndex = klines.length - bbResults.length;
    return bbResults.map((result, index) => {
      const currentTimestamp = timestamps[startIndex + index];
      const currentPrice = closePrices[startIndex + index];
      const bandwidth = result.upper - result.lower;

      // 计算价格带宽比率 (Price Bandwidth Ratio)
      // 用于表示当前价格在布林带中的相对位置
      const pb = bandwidth > 0
        ? (currentPrice - result.lower) / bandwidth
        : 0.5;

      return {
        timestamp: currentTimestamp,
        upper: result.upper,
        middle: result.middle,
        lower: result.lower,
        pb: pb
      };
    });
  }

  // 将OKX API返回的格式化K线数据转换为指标计算所需的格式
  convertFormattedKlines(formattedKlines: any[]): TAKlineData[] {
    return formattedKlines.map(kline => ({
      timestamp: kline.timestamp,
      open: kline.open,
      high: kline.high,
      low: kline.low,
      close: kline.close,
      volume: kline.volume || kline.volumeCcy || 0
    }));
  }

  /**
   * 统一指标计算接口
   * @param klineData K线数据
   * @param indicatorType 指标类型
   * @param options 计算选项
   * @returns 指标计算结果
   */
  calculateIndicator(
    klineData: TAKlineData[],
    indicatorType: string,
    options: any
  ): RSIResult[] | MACDResult[] | BOLLResult[] | SMAResult[] | EMAResult[] | ATRResult[] {
    switch (indicatorType.toUpperCase()) {
      case 'RSI':
        return this.calculateRSI(klineData, {
          period: options.period || 14,
        });

      case 'MACD':
        return this.calculateMACD(klineData, {
          fastPeriod: options.fastPeriod || 12,
          slowPeriod: options.slowPeriod || 26,
          signalPeriod: options.signalPeriod || 9,
        });

      case 'BOLL':
        return this.calculateBollingerBands(klineData, {
          period: options.period || 20,
          stdDev: options.stdDev || 2,
        });

      case 'SMA':
        return this.calculateSMA(klineData, {
          period: options.period || 20,
        });

      case 'EMA':
        return this.calculateEMA(klineData, {
          period: options.period || 20,
        });

      case 'ATR':
        return this.calculateATR(klineData, {
          period: options.period || 14,
        });

      default:
        throw new Error(`不支持的指标类型: ${indicatorType}`);
    }
  }

  /**
   * 分析指标结果
   * @param indicatorType 指标类型
   * @param result 指标结果
   * @returns 分析结果
   */
  analyzeIndicator(indicatorType: string, result: any): { status: string, message: string } {
    // 根据不同指标类型提供分析
    switch (indicatorType.toUpperCase()) {
      case 'RSI':
        return this.analyzeRSI(result.value || result.values?.value);

      case 'MACD':
        return this.analyzeMACD(result);

      case 'BOLL':
        return this.analyzeBollingerBands(result);

      default:
        return { status: 'unknown', message: '未知指标类型' };
    }
  }

  // 修改MACD分析方法中的字段引用
  analyzeMACD(result: any): { status: string, message: string } {
    // 尝试从result中获取DIF、DEA和MACD字段，兼容新旧两种命名
    const dif = result.DIF !== undefined ? result.DIF :
      (result.values?.DIF !== undefined ? result.values.DIF :
        (result.macd !== undefined ? result.macd : result.values?.macd || 0));

    const dea = result.DEA !== undefined ? result.DEA :
      (result.values?.DEA !== undefined ? result.values.DEA :
        (result.signal !== undefined ? result.signal : result.values?.signal || 0));

    const macd = result.MACD !== undefined ? result.MACD :
      (result.values?.MACD !== undefined ? result.values.MACD :
        (result.histogram !== undefined ? result.histogram : result.values?.histogram || 0));

    if (macd > 0 && dif > 0) {
      return {
        status: 'bullish',
        message: 'MACD柱状图为正且DIF线在零轴上方，看涨信号'
      };
    } else if (macd < 0 && dif < 0) {
      return {
        status: 'bearish',
        message: 'MACD柱状图为负且DIF线在零轴下方，看跌信号'
      };
    } else if (macd > 0) {
      return {
        status: 'neutral-bullish',
        message: 'MACD柱状图为正，偏向多头'
      };
    } else {
      return {
        status: 'neutral-bearish',
        message: 'MACD柱状图为负，偏向空头'
      };
    }
  }

  // 添加布林带分析方法
  analyzeBollingerBands(result: any): { status: string, message: string } {
    const upper = result.upper || result.values?.upper || 0;
    const middle = result.middle || result.values?.middle || 0;
    const lower = result.lower || result.values?.lower || 0;
    const pb = result.pb || result.values?.pb || 0.5;

    if (pb >= 0.95) {
      return {
        status: 'overbought',
        message: '价格接近布林带上轨，可能超买'
      };
    } else if (pb <= 0.05) {
      return {
        status: 'oversold',
        message: '价格接近布林带下轨，可能超卖'
      };
    } else if (pb > 0.5) {
      return {
        status: 'neutral-bullish',
        message: '价格在布林带中上方'
      };
    } else {
      return {
        status: 'neutral-bearish',
        message: '价格在布林带中下方'
      };
    }
  }

  /**
   * 使用最新K线数据更新指标值
   * @param existingResults 现有的指标结果
   * @param latestKline 最新的K线数据
   * @param indicatorType 指标类型
   * @param options 指标计算选项
   * @returns 更新后的指标结果
   */
  updateIndicatorWithLatestKline<T extends RSIResult | MACDResult | BOLLResult>(
    existingResults: T[],
    latestKline: TAKlineData,
    indicatorType: string,
    options: any
  ): T[] {
    if (!existingResults || existingResults.length === 0) {
      return existingResults;
    }

    // 创建一个新的数组，其中包含所有历史数据点
    const originalData = existingResults.map(result => {
      const timestamp = typeof result.timestamp === 'string' ?
        parseInt(result.timestamp) : result.timestamp;

      // 我们需要模拟原始的K线数据，只使用收盘价（这是简化版）
      return {
        timestamp,
        close: this.getClosePrice(result),
        open: this.getClosePrice(result),
        high: this.getClosePrice(result),
        low: this.getClosePrice(result),
        volume: 0
      } as TAKlineData;
    });

    // 添加最新的K线数据
    const combinedData = [...originalData, latestKline].sort((a, b) => {
      const tsA = typeof a.timestamp === 'string' ? parseInt(a.timestamp) : a.timestamp;
      const tsB = typeof b.timestamp === 'string' ? parseInt(b.timestamp) : b.timestamp;
      return tsA - tsB;
    });

    // 重新计算指标
    const updatedResults = this.calculateIndicator(combinedData, indicatorType, options);

    // 返回更新后的结果
    return updatedResults as T[];
  }

  /**
   * 从指标结果中提取收盘价（用于重建K线）
   */
  private getClosePrice(result: any): number {
    // 对于布林带，使用中间轨作为收盘价
    if (result.middle !== undefined) {
      return result.middle;
    }
    // 对于RSI，使用上一次计算的结果（简化实现）
    // 实际上RSI计算需要完整的价格序列，这只是一个近似
    return 0;  // 这里理想情况应该保存原始K线，但为简洁性先返回0
  }

  /**
   * 从不同类型的指标结果中提取值
   * @param result 指标结果
   * @returns 标准化的值对象
   */
  private extractValues(result: any): Record<string, number> {
    // 根据不同指标类型提取关键值
    if (result.value !== undefined) {
      // RSI 格式
      return { value: result.value };
    } else if (result.DIF !== undefined || result.macd !== undefined) {
      // MACD 格式，支持新旧命名
      return {
        DIF: result.DIF !== undefined ? result.DIF : result.macd,
        DEA: result.DEA !== undefined ? result.DEA : result.signal,
        MACD: result.MACD !== undefined ? result.MACD : result.histogram
      };
    } else if (result.upper !== undefined) {
      // 布林带格式
      return {
        upper: result.upper,
        middle: result.middle,
        lower: result.lower,
        pb: result.pb || 0
      };
    } else {
      // 通用格式，移除timestamp和type字段
      const values = { ...result };
      delete values.timestamp;
      delete values.type;
      return values;
    }
  }
} 